/*-------------------------------------------------------------------------
 *
 * rewriteSupport.c
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/rewrite/rewriteSupport.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/indexing.h"
#include "catalog/pg_rewrite.h"
#include "rewrite/rewriteSupport.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"


/*
 * 是否存在具有给定名称的规则？
 */
bool IsDefinedRewriteRule(Oid fc_owningRel, const char *fc_ruleName)
{
	return SearchSysCacheExists2(RULERELNAME,
								 ObjectIdGetDatum(fc_owningRel),
								 PointerGetDatum(fc_ruleName));
}


/*
 * SetRelationRuleStatus
 *		设置 pg_class 中关系的 relhasrules 字段的值。
 *
 * 注意：调用者必须持有适当的锁定关系。
 *
 * 注意：此操作的一个重要副作用是发送 SI 失效
 * 消息到所有后端 —— 包括我 —— 导致 relcache
 * 条目被刷新或更新为表的新规则集。
 * 即使发现 pg_class 行中不需要更改，这也必须发生。
 */
void SetRelationRuleStatus(Oid fc_relationId, bool fc_relHasRules)
{
	Relation	fc_relationRelation;
	HeapTuple	fc_tuple;
	Form_pg_class fc_classForm;

	/*
	 * 在 pg_class 中查找要更新的元组，使用 syscache 进行查找。
	 */
	fc_relationRelation = table_open(RelationRelationId, RowExclusiveLock);
	fc_tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(fc_relationId));
	if (!HeapTupleIsValid(fc_tuple))
		elog(ERROR, "cache lookup failed for relation %u", fc_relationId);
	fc_classForm = (Form_pg_class) GETSTRUCT(fc_tuple);

	if (fc_classForm->relhasrules != fc_relHasRules)
	{
		/* 执行更新 */
		fc_classForm->relhasrules = fc_relHasRules;

		CatalogTupleUpdate(fc_relationRelation, &fc_tuple->t_self, fc_tuple);
	}
	else
	{
		/* 无需更改元组，但仍强制重新构建 relcache */
		CacheInvalidateRelcacheByTuple(fc_tuple);
	}

	heap_freetuple(fc_tuple);
	table_close(fc_relationRelation, RowExclusiveLock);
}

/*
 * 查找规则 oid。
 *
 * 如果 missing_ok 为 false，则在未找到规则名称时抛出错误。 如果
 * 为 true，则仅返回 InvalidOid。
 */
Oid get_rewrite_oid(Oid fc_relid, const char *fc_rulename, bool fc_missing_ok)
{
	HeapTuple	fc_tuple;
	Form_pg_rewrite fc_ruleform;
	Oid			fc_ruleoid;

	/* 查找规则的 pg_rewrite 元组，获取其 OID */
	fc_tuple = SearchSysCache2(RULERELNAME,
							ObjectIdGetDatum(fc_relid),
							PointerGetDatum(fc_rulename));
	if (!HeapTupleIsValid(fc_tuple))
	{
		if (fc_missing_ok)
			return InvalidOid;
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("rule \"%s\" for relation \"%s\" does not exist",
						fc_rulename, get_rel_name(fc_relid))));
	}
	fc_ruleform = (Form_pg_rewrite) GETSTRUCT(fc_tuple);
	Assert(fc_relid == fc_ruleform->ev_class);
	fc_ruleoid = fc_ruleform->oid;
	ReleaseSysCache(fc_tuple);
	return fc_ruleoid;
}
